package xaj.weavingtest.ast.istype;

import polyglot.util.Position;
import abc.weaving.aspectinfo.AbcType;
import abc.weaving.aspectinfo.LocalPointcutVars;
import abc.weaving.aspectinfo.Pointcut;
import abc.weaving.aspectinfo.ThisAny;
import abc.weaving.aspectinfo.ThisVar;
import abc.weaving.aspectinfo.Unification;
import abc.weaving.aspectinfo.VarBox;
import abc.weaving.aspectinfo.Var;
import abc.weaving.aspectinfo.ArgType;
import abc.weaving.matching.WeavingEnv;
import abc.weaving.residues.CheckType;
import abc.weaving.residues.ContextValue;
import abc.weaving.residues.Residue;
import abc.weaving.residues.WeavingVar;

public class ThisType_isType extends ThisAny {
	private AbcType type;

    public ThisType_isType(AbcType type,Position pos) {
	super(pos);
	this.type = type;
    }

    /** Get the type that is matched against <code>this</code>
     *  by this <code>this</code> pointcut.
     */
    public AbcType getType() {
	return type;
    }

    public String toString() {
	return "this("+type+")";
    }

    /*
    protected Residue matchesAt(WeavingEnv we,ContextValue cv) {
		return CheckType.construct(cv,type.getSootType());
    }
    */
    
    protected Residue matchesAt(WeavingEnv we,ContextValue cv) {
    	
    	Var var = (Var) cv.getSootValue();
    	WeavingVar wvar = we.getWeavingVar(var);
    	System.out.println("em THISTYPE: matching "+wvar.hashCode()+" with "+cv);
    	MapValues.put(wvar, cv);
    	
    	return CheckType.construct(cv,type.getSootType());
    }

	/* (non-Javadoc)
	 * @see abc.weaving.aspectinfo.Pointcut#unify(abc.weaving.aspectinfo.Pointcut, java.util.Hashtable, java.util.Hashtable, abc.weaving.aspectinfo.Pointcut)
	 */
	public boolean unify(Pointcut otherpc, Unification unification) {

		if (otherpc.getClass() == this.getClass()) {
			AbcType othertype = ((ThisType_isType)otherpc).getType();
			if (type.equals(othertype)) {
				unification.setPointcut(this);
				return true;
			} else return false;
		} else if ((otherpc.getClass() == ThisVar.class) && 
				   (!unification.unifyWithFirst())) {
			// If the other pc is a ThisVar with the same type as this, can unify
			// BUT only if we are not restricted to returning THIS
			if (abc.main.Debug.v().debugPointcutUnification)
				System.out.println("Trying to unify a ThisType_isType "+this+" with a ThisVar: "+otherpc);
			ThisVar othertv = (ThisVar)otherpc;
			if (this.getType().equals(unification.getType2(othertv.getVar().getName()))) {
				if (abc.main.Debug.v().debugPointcutUnification)
					System.out.println("Succeeded!");
				unification.setPointcut(othertv);
				unification.put1(othertv.getVar(), new VarBox());
				return true;
			} else return false;
		} else // Do the right thing if otherpc was a local vars pc
			return LocalPointcutVars.unifyLocals(this,otherpc,unification);

	}
}
